package server

import (
	"github.com/deckarep/golang-set"
	"github.com/guotie/gogb2312"
	"github.com/sirupsen/logrus"
	"strings"
)

const (
	cmd_group_delete = "UNGROUP"
	cmd_group_insert = "GROUP"
	cmd_group_list   = "LIST"
	cmd_group_query  = "QUERY"
)

//房间->client
var groupMap map[string]mapset.Set

//client->房间
var clientMap map[*Client]string

/**
启动服务器
*/
func RunServer(port string) {

	groupMap = make(map[string]mapset.Set)
	clientMap = make(map[*Client]string)

	server := New("0.0.0.0" + port)

	server.OnNewClient(func(c *Client) {
		// new client connected
		// lets send some message
		c.Send("Hello")
		logrus.WithFields(logrus.Fields{
			"ip": c.conn.RemoteAddr(),
		}).Info("new client connected")
	})
	server.OnNewMessage(func(c *Client, message string) {
		// new message received
		b, e := msg_prase(c, message)
		responce_msg(c, b, e)

		message, _, _, _ = gogb2312.ConvertGB2312String(message)
		logrus.WithFields(logrus.Fields{
			"msg": message,
		}).Debug("new message")

	})

	server.OnClientConnectionClosed(func(c *Client, err error) {
		// connection with client lost
		logrus.WithFields(logrus.Fields{
			"ip": c.conn.RemoteAddr(),
		}).Info("new client disconnected")

		//从房间删除
		client_leave_group(c)
	})

	logrus.Info("server started at port" + port)
	server.Listen()

}

func client_join_group(c *Client, g string) (bool, string) {
	group, ok := clientMap[c]
	clients, ok1 := groupMap[g]
	if ok {
		//已经加入过了分组，无操作
		logrus.WithFields(logrus.Fields{
			"ip":    c.conn.RemoteAddr(),
			"alias": c.alias,
			"group": group,
		}).Info("client has joined group")
		return false, group
	}
	if !ok1 {
		//新建房间
		list := mapset.NewSetWith(c)
		//更新map
		groupMap[g] = list
		clientMap[c] = g
	} else {
		clients.Add(c)
		//更新map
		groupMap[g] = clients
		clientMap[c] = g
	}
	logrus.WithFields(logrus.Fields{
		"ip":    c.conn.RemoteAddr(),
		"alias": c.alias,
		"group": g,
	}).Info("client join group")
	return true, g
}

func client_leave_group(c *Client) string {
	group, ok := clientMap[c]
	clients, ok1 := groupMap[group]
	if !ok || !ok1 {
		//不存在房间则无反应
		group = "null"
	} else {
		//删除客户端
		clients.Remove(c)
		delete(clientMap, c)
	}
	logrus.WithFields(logrus.Fields{
		"ip":    c.conn.RemoteAddr(),
		"alias": c.alias,
		"group": group,
	}).Info("client leave group")
	return group
}

/**
解析消息
*/
func msg_prase(c *Client, msg string) (broadcast interface{}, echo interface{}) {
	broadcast = msg //组播到整个房间的消息，不包含自己。默认，如果设备没有加入房间，那就是发给自己
	echo = nil      //返回给客户端自己

	//判断是不是命令
	test := strings.Index(msg, "CMD")
	if test > -1 && len(msg) > 6 {
		//去掉\r\n
		turn := strings.Index(msg, "\r\n")
		if turn > -1 {
			msg = msg[:turn]
		}
		cmds := strings.Split(msg, ",")
		if len(cmds) < 2 {
			return broadcast, echo
		} else {
			cmd_type := cmds[1]
			if strings.Compare(cmd_type, cmd_group_insert) == 0 && len(cmds) > 2 {
				//加入房间,名称长度不为0
				group := cmds[2] //参数1
				//存在客户端别名
				if (len(cmds) > 3) && len(cmds[3]) > 1 {
					c.alias = cmds[3]
				}

				if len(group) > 0 {
					stat, g := client_join_group(c, group)
					if stat {
						echo = "Join Group:" + g
						broadcast = nil
					} else {
						echo = "has Joined Group:" + g
						broadcast = nil
					}
				}
			} else if strings.Compare(cmd_type, cmd_group_delete) == 0 {
				//退出房间
				group := client_leave_group(c)
				echo = "Leave Group:" + group
				broadcast = nil
			} else if strings.Compare(cmd_type, cmd_group_list) == 0 {
				//查询房间里面全部客户端
				group, ok := clientMap[c]
				clients, ok1 := groupMap[group]

				if !ok || !ok1 {
					//没加入房间则无反应
					echo = "Not Join Group!"
					broadcast = nil
				} else {
					//返回列表
					it := clients.Iterator()
					var builder strings.Builder
					builder.WriteString("Group List")
					for ele := range it.C {
						builder.WriteString(",")
						con := ele.(*Client)
						//存在别名打印别名加ip
						if len(con.alias) > 0 {
							builder.WriteString(con.alias)
							builder.WriteString("->")
						}
						builder.WriteString(con.conn.RemoteAddr().String())
					}
					echo = builder.String()
					broadcast = nil
				}

			} else if strings.Compare(cmd_type, cmd_group_query) == 0 {
				//查询自己在什么房间
				//查询房间里面全部客户端
				group, ok := clientMap[c]
				if !ok {
					//没加入房间则无反应
					echo = "Not Join Group!"
					broadcast = nil
				} else {
					//返回房间名称
					var builder strings.Builder
					builder.WriteString("Group:")
					builder.WriteString(group)
					echo = builder.String()
					broadcast = nil
				}
			}
		}
	}
	return broadcast, echo
}

/**
响应客户端
*/
func responce_msg(c *Client, broad interface{}, echo interface{}) {
	//直接发给客户端
	if echo != nil {
		c.Send(echo.(string))
	}
	//房间内组播
	if broad != nil {
		msg := broad.(string)
		group, ok := clientMap[c]
		clients := groupMap[group]
		//看看设备是否加入了房间，没有加入回复自己, 加入了组播
		if !ok {
			c.Send(msg)
		} else {
			//找到组内其他客户端
			it := clients.Iterator()
			for ele := range it.C {
				if ele != c {
					ele.(*Client).Send(msg)
				}
			}
		}

	}
}
